package cn.com.bsoft.mobile.service


import cn.com.bsoft.mobile.dao.AppMessageJobDao
import cn.com.bsoft.mobile.entity.AppMessageJob
import cn.com.bsoft.mobile.entity.MobileApp
import cn.com.bsoft.mobile.model.DeviceType
import cn.net.xyan.blossom.core.service.ConfigService
import cn.net.xyan.blossom.kotlin.*
import com.turo.pushy.apns.ApnsClient
import com.turo.pushy.apns.ApnsClientBuilder
import com.turo.pushy.apns.ApnsPushNotification
import com.turo.pushy.apns.PushNotificationResponse
import com.turo.pushy.apns.auth.ApnsSigningKey
import com.turo.pushy.apns.util.ApnsPayloadBuilder
import com.turo.pushy.apns.util.SimpleApnsPushNotification
import com.turo.pushy.apns.util.TokenUtil
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.scheduling.annotation.Async
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.transaction.annotation.Transactional
import java.io.ByteArrayInputStream
import java.util.*
import javax.annotation.PostConstruct
import kotlin.collections.HashMap

@AllOpen
class AppleApnsService{

    @Autowired
    lateinit var configService: ConfigService

    @Autowired
    lateinit var jobDao:AppMessageJobDao

    @Autowired
    lateinit var deviceService:MobileDeviceService

    @Autowired
    lateinit var appService:MobileAppService

    val clientCache:MutableMap<String,ApnsClient> = HashMap()
    val clientDebugCache:MutableMap<String,ApnsClient> = HashMap()

    companion object {
        const val KEYAPNSHost = "KEYAPNSHost"
        const val KEYAPNSTeamID = "KEYAPNSTeamID"
        const val KEYAPNSKeyID = "KEYAPNSKeyID"
        const val KEYAPNSSecret = "KEYAPNSSecret"
    }

    @PostConstruct
    fun setup(){

        //var input = javaClass.classLoader.getResourceAsStream("JieYiAuthKey.p8")

        configService.setupVariable(KEYAPNSHost,ApnsClientBuilder.DEVELOPMENT_APNS_HOST,"苹果推送服务器")
        configService.setupVariable(KEYAPNSTeamID,"2WWTW3X3M3","苹果推送teamId")
        configService.setupVariable(KEYAPNSKeyID,"GX326C3552","苹果推送keyId")
        configService.setupVariable(KEYAPNSSecret,
                "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR1RBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJIa3dkd0lCQVFRZ3Q2M2l3WDRUZHNRYkEzR0sKR1IzeU03cW9aUGxiWmdyQVY2N1c0bEZIYjNTZ0NnWUlLb1pJemowREFRZWhSQU5DQUFTQzRlYUMvUlJoTVlWcQpUU1lzV3l1NnhpN1V6WkFqbDJ6NzhycXM1Y2REdlJreFlMbVpzWU1POGVrY3phWU5MN3V1V0diaTcxekZHaTFuCmxHNDIrQm1SCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=",
                "苹果推送密钥 P8格式文件")

//        val host = configService.queryValue(KEYAPNSHost)
//        val teamId = configService.queryValue(KEYAPNSTeamID)
//        val keyId = configService.queryValue(KEYAPNSKeyID)
//
//        val secret = configService.queryValue(KEYAPNSSecret)
//
//        var bytes = secret?.decodeBase64()
//
//        var input = ByteArrayInputStream(bytes)

        appService.allApp().filter {
            (it.type == DeviceType.iOS.value)
            && (it.teamID!=null)
            && (it.pushKeyID != null && it.pushKeyID!!.isNotEmpty())
            && (it.pushSecret != null)
        }.forEach {
            updateClient(it)
        }

//        apnsClient = ApnsClientBuilder()
//                .setApnsServer(host)
//                .setSigningKey(ApnsSigningKey.loadFromInputStream(input,teamId, keyId))
//                .build()
    }


    fun updateClient(app:MobileApp,host:String):ApnsClient?{
        try {

            var bytes = app.pushSecret?.decodeBase64()

            var input = ByteArrayInputStream(bytes)

            return   ApnsClientBuilder()
                    .setApnsServer(host)
                    .setSigningKey(ApnsSigningKey.loadFromInputStream(input, app.teamID, app.pushKeyID))
                    .build()

            //clientCache[app.nativeID] = client

        }catch (e:Throwable){
            logger.error(e.stackTraceMessage)
            return null
        }
    }

    fun updateClient(app:MobileApp):ApnsClient?{
        try {

            var client:ApnsClient? = updateClient(app,ApnsClientBuilder.PRODUCTION_APNS_HOST)

            if (client != null)
                clientCache[app.nativeID] = client

            client = updateClient(app,ApnsClientBuilder.DEVELOPMENT_APNS_HOST)

            if (client != null)
                clientDebugCache[app.nativeID] = client

            return client?:null
        }catch (e:Throwable){
            logger.error(e.stackTraceMessage)
            return null
        }
    }

    @Async
    fun doSendJobAsync(job:AppMessageJob){
        doSendJob(job)
    }


    fun sendApnsMsg(pushNotification: ApnsPushNotification,appID:String): PushNotificationResponse<*>? {
        var apnsClient = clientCache[appID]?:clientDebugCache[appID]?:throw StatusAndMessageError("$appID 没有配置推送信息")

        var sendNotificationFuture = apnsClient?.sendNotification(pushNotification)

        var pushNotificationResponse = sendNotificationFuture?.get()

        return if (true == pushNotificationResponse?.isAccepted) {
            pushNotificationResponse
        } else {
            apnsClient = clientDebugCache[appID]?:throw StatusAndMessageError("$appID 没有配置推送信息")

            sendNotificationFuture = apnsClient?.sendNotification(pushNotification)

            sendNotificationFuture?.get()
        }
    }

    @Transactional
    fun doSendJob(job:AppMessageJob){
        val now = Date()



        val msg = job.message
        val app = job.app

        val payloadBuilder = ApnsPayloadBuilder()
        payloadBuilder.setAlertBody(msg.messageBody)
        payloadBuilder.setAlertTitle(msg.msgTitle)
        payloadBuilder.addCustomProperty("extra",msg.extra?:"")
        payloadBuilder.addCustomProperty("id",msg.messageID)
        payloadBuilder.addCustomProperty("action",msg.action?:"")

        val payload = payloadBuilder.buildWithDefaultMaximumLength()

        val pushID = deviceService.codeForNotifyPush(job.user,app,job.device)

        if (pushID == null || pushID.isEmpty())
            return

        val token = TokenUtil.sanitizeTokenString(pushID)

        val pushNotification = SimpleApnsPushNotification(token,
                //"XY.cn-com-bsoft-jy-pushDemo",
                app.nativeID,
                payload)

        //val apnsClient = clientCache[job.app.nativeID]?:throw StatusAndMessageError("${app.nativeID} 没有配置推送信息")

        //val sendNotificationFuture = apnsClient.sendNotification(pushNotification)

        val pushNotificationResponse = sendApnsMsg(pushNotification,job.app.nativeID)//sendNotificationFuture.get()

        if (true == pushNotificationResponse?.isAccepted) {
            job.sentDate = Date()
        } else {
            val reason = pushNotificationResponse?.rejectionReason

            logger.error(reason)

            val diff = now.time - job.createDate.time
            val next = Date(now.time + diff *2)

            job.nextSendDate = next
            job.retryCount = job.retryCount+1
        }

        jobDao.saveAndFlush(job)
    }

    @Scheduled(cron = "0 0/1 * * * ?")
    fun scheduleSend(){
        val now = Date()

        val start = Date(now.time - 1000*3600*1)

        val jobs = jobDao.queryUnSent(DeviceType.iOS.value,start,now)

        jobs.forEach {
            doSendJobAsync(it)
        }
    }

}